package org.openwebtop.sunshine.subversion;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openwebtop.sunshine.model.Component;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.DefaultSVNRepositoryPool;
import org.tmatesoft.svn.core.wc.ISVNRepositoryPool;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

public class SubversionClientFactory {
	private final static Log LOG = LogFactory.getLog(SubversionClientFactory.class);
	private final Map<String, ISVNRepositoryPool> repositoryPoolMap;

	static {
		DAVRepositoryFactory.setup();
		SVNRepositoryFactoryImpl.setup();
		FSRepositoryFactory.setup();
	}

	public SubversionClientFactory() {
		this.repositoryPoolMap = new HashMap<String, ISVNRepositoryPool>();

		if (LOG.isDebugEnabled()) {
			LOG.debug("SubversionClientFactory has been initialized.");
		}
	}

	public SubversionClient getSubversionClient(Component component) throws Exception {
		if (component != null) {
			final SVNRepository repository = getRepository(component);

			if (repository != null) {
				return new SubversionClientImpl(repository, component.getEncoding());
			}
		}

		return null;
	}

	public void destroy() {
		for (ISVNRepositoryPool pool : repositoryPoolMap.values()) {
			pool.dispose();
		}

		if (LOG.isDebugEnabled()) {
			LOG.debug("SubversionClientFactory has been destroyed.");
		}
	}

	private SVNRepository getRepository(Component component) throws Exception {
		if (component != null) {
			final SVNURL url = getUrl(component);
			ISVNRepositoryPool pool = repositoryPoolMap.get(component.getRepositoryLocation());

			if (pool == null) {
				final ISVNAuthenticationManager authManager = SVNWCUtil.createDefaultAuthenticationManager(component.getUsername(), component.getPassword());
				pool = new DefaultSVNRepositoryPool(authManager, null, 3000, false);
				repositoryPoolMap.put(component.getRepositoryLocation(), pool);

				if (LOG.isDebugEnabled()) {
					LOG.debug(String.format("Repository pool has been created. (%s)", url));
				}
			}

			return pool.createRepository(url, true);
		}

		return null;
	}

	private SVNURL getUrl(Component component) throws Exception {
		if (component != null) {
			final String url = component.getRepositoryLocation() + "/" + component.getName();

			return SVNURL.parseURIEncoded(url);
		}

		return null;
	}

}
